/*
  S.M.A.C.K - An operating system kernel
  Copyright (C) 2010,2011 Mattias Holm and Kristian Rietveld
  For licensing and a full list of authors of the kernel, see the files
  COPYING and AUTHORS.
*/

#include <interrupt.h>
#include <stddef.h>

struct irq_handler_entry
{
  irq_handler_func_t func;
  void *func_data;
}
irq_handlers[N_IRQS];

void
interrupt_init(void)
{
  int i;

  hw_interrupt_init();

  for (i = 0; i < N_IRQS; i++)
    irq_handlers[i].func = NULL;
}

void
interrupt_call_handler(uint32_t irq)
{
  if (irq_handlers[irq].func != NULL)
    (* irq_handlers[irq].func) (irq_handlers[irq].func_data);
}

void
interrupt_register_irq_handler(uint32_t            irq,
                               irq_handler_func_t  func,
                               void               *func_data)
{
  uint32_t flags;

  flags = save_flags();

  disable_interrupts();
  disable_fast_interrupts();

  /* We will not overwrite already registered IRQ handlers.  Shared
   * IRQ support is likely needed in the future.  Also see the
   * comment below.
   */
  if (irq_handlers[irq].func == NULL)
    {
      irq_handlers[irq].func = func;
      irq_handlers[irq].func_data = func_data;
    }

  restore_flags(flags);
}

/* The func and func_data arguments are by now not strictly needed.
 * However, when we will implement support for shared interrupts in
 * the future this data will be required to be able to deregister
 * only the wished irq handler.
 */
void
interrupt_deregister_irq_handler(uint32_t            irq,
                                 irq_handler_func_t  func,
                                 void               *func_data)
{
  uint32_t flags;

  flags = save_flags();

  disable_interrupts();
  disable_fast_interrupts();

  if (irq_handlers[irq].func == func)
    {
      irq_handlers[irq].func = NULL;
      irq_handlers[irq].func_data = NULL;
    }

  restore_flags(flags);
}
